package com.gitee.l0km.codegen.thrift.plugin;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;

import com.gitee.l0km.codegen.base.CodeGenUtils;
import com.gitee.l0km.codegen.base.plugin.BasePlugin;
import com.gitee.l0km.codegen.thrift.ThriftServiceDecoratorConfiguration;
import com.gitee.l0km.codegen.thrift.ThriftServiceDecoratorGenerator;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;

/**
 * {@link ThriftServiceDecoratorGenerator}生成器运行插件
 * @author guyadong
 *
 */
@Mojo(name = "generate",requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
public class ThriftServicePlugin extends BasePlugin{
	/**
	 * interface class name
	 */
	@Parameter(required = true,property="codegen.thrift.interfaceClass")
	private String interfaceClass;
	/**
	 * reference class name
	 */
	@Parameter(required = false,property="codegen.thrift.refClass")
	private String refClass = null;
	/**
	 * package name for generate class
	 */
	@Parameter(alias="package",required =true,property="codegen.thrift.pkg")
	private String pkg ;
	/**
	 * package for thrift client class
	 */
	@Parameter(required = false,property="codegen.thrift.thriftPackage")
	private String thriftPackage = null;
	@Parameter(alias="gt",required =true,property="codegen.thrift.taskType")
	private String taskType;
	/**
	 * language of  generated code 
	 */
	@Parameter(alias="lg",defaultValue="JAVA",property="codegen.thrift.language")
	private String language;
	/**
	 * config file
	 */
	@Parameter(alias="cg",property="codegen.thrift.config")
	private String config;
	/**
	 * path list of source separated by semicolon
	 */
	@Parameter(property="codegen.thrift.sourcePath")
	private String sourcePath;
	/**
	 * Specifies the paths where javadoc will look for referenced classes (.class files),
	 * Ignored since 3.3.0
	 */
	@Parameter(property="codegen.thrift.classPath")
	private String classPath;
	/**
	 * comma separated tag list for filtering service port,default:empty
	 */
	@Parameter(property="codegen.thrift.requiredTags")
	private String requiredTags;
	/**
	 * common types which will be skip for generation,splited with [,]without blank space
	 */
	@Parameter(property="codegen.thrift.commonTypes")
	private String commonTypes;
	/**
	 * program name for ERPC_PROXY task
	 */
	@Parameter(property="codegen.thrift.erpcProgram")
	private String erpcProgram;
	/**
	 * prefix for service method name for ERPC_PROXY task
	 */
	@Parameter()
	private String erpcPortPrefix;
	/**
	 * exclude service methods names,splited with [,]without blank space
	 */
	@Parameter(property="codegen.thrift.excludeMethods")
	private Map<String,String> excludeMethods = ImmutableMap.of();
	/**
	 * include service methods names,splited with [,]without blank space
	 */
	@Parameter(property="codegen.thrift.includeMethods")
	private Map<String,String> includeMethods = ImmutableMap.of();
	/**
	 * exclude fields for struct class name,such {@code '<com.simple.class.ClassA>fieldname1,fieldname2</com.simple.class.ClassA>'} 
	 */
	@Parameter(property="codegen.thrift.excludeFields")
	private Map<String,String> excludeFields = ImmutableMap.of();
	/**
	 * thrift service class with {@code @ThriftService} annotation
	 */
	@Parameter(property="codegen.thrift.thriftServiceClass")
	private String thriftServiceClass;
	/**
	 * thrift service port that erpc proxy forward request to,required by ERPC_PROXY task
	 */
	@Parameter(property="codegen.thrift.erpcForwardPort")
	private int erpcForwardPort = 0;
	/**
	 * service port for erpc porxy,required by ERPC_PROXY task
	 */
	@Parameter(property="codegen.thrift.erpcProxyPort")
	private int erpcProxyPort = 0;
	/**
	 * default value for annotation @max_length,default 256,used by ERPC_PROXY task
	 */
	@Parameter(property="codegen.thrift.defaultMaxLength")
	private int defaultMaxLength = 0;
	/**
	 * max length for output error message buffer of  each service port,default 256,used by ERPC_PROXY task
	 */
	@Parameter(property="codegen.thrift.errmsgMaxLength")
	private int errmsgMaxLength = 0;
	/**
	 * output size for binary_t,default 256,used by ERPC_PROXY task
	 */
	@Parameter(property="codegen.thrift.binaryOutputSize")
	private int binaryOutputSize = 0;
	/**
	 * extensive thrift struct class names,splited with [,]without blank space
	 */
	@Parameter(property="codegen.thrift.extStructs")
	private String extStructs;
	/**
	 * exclude templates which will be skip for generation,splited with [,]without blank space
	 */
	@Parameter()
	private String excludeVMs;
	/**
	 * include templates for generation,splited with [,]without blank space
	 */
	@Parameter()
	private String includeVMs;
	public ThriftServicePlugin() {
	}
	@Override
	protected String getTemplateFolder() {
		return ThriftServiceDecoratorConfiguration.DEFAULT_TEMPLATE_FOLDER;
	}

	@Override
	public void execute() throws MojoExecutionException, MojoFailureException {
		ThriftServiceDecoratorGenerator.main(makeArgs().toArray(new String[0]));
	}

	@Override
	protected List<String> makeArgs() {
		List<String> args = super.makeArgs();
		args.add("--" + ThriftServiceDecoratorConfiguration.INTERFACE_CLASS_OPTION_LONG);
		args.add(interfaceClass);
		args.add("--" + ThriftServiceDecoratorConfiguration.PACKAGE_OPTION_LONG);
		args.add(pkg);
		if(!Strings.isNullOrEmpty(refClass)){
			args.add("--" + ThriftServiceDecoratorConfiguration.REFERENCE_CLASS_OPTION_LONG);
			args.add(refClass);
		}
		args.add("--" + ThriftServiceDecoratorConfiguration.TASK_TYPE_OPTION_LONG);
		args.add(taskType);
		args.add("--" + ThriftServiceDecoratorConfiguration.LANGUAGE_OPTION_LONG);
		args.add(language);
		if(!Strings.isNullOrEmpty(thriftPackage)){
			args.add("--" + ThriftServiceDecoratorConfiguration.THRIFT_CLIENT_PKG_OPTION_LONG);
			args.add(thriftPackage);
		}
		if(!Strings.isNullOrEmpty(config)){
			args.add("--" + ThriftServiceDecoratorConfiguration.CONFIG_OPTION_LONG);
			args.add(config);
		}
		if(null != sourcePath){
			args.add("--" + ThriftServiceDecoratorConfiguration.SOURCE_PREFIX_OPTION_LONG);
			args.add(sourcePath);
		}
		classPath = buildClasspath();
		args.add("--" + ThriftServiceDecoratorConfiguration.CLASS_PATH_OPTION_LONG);
		args.add(classPath);
		/** 初始项目ClassLoader */
		CodeGenUtils.initProjectClassLoader(classPath, getClass().getClassLoader());
		if(null != requiredTags){
			args.add("--" + ThriftServiceDecoratorConfiguration.TAGS_OPTION_LONG);
			args.add(requiredTags);
		}
		if(null != commonTypes){
			args.add("--" + ThriftServiceDecoratorConfiguration.COMMON_TYPES_OPTION_LONG);
			args.add(commonTypes);
		}
		if(null != erpcProgram){
			args.add("--" + ThriftServiceDecoratorConfiguration.ERPC_PROGRAM_OPTION_LONG);
			args.add(erpcProgram);
		}
		if(null != erpcPortPrefix){
			args.add("--" + ThriftServiceDecoratorConfiguration.ERPC_PORT_PREFIX_OPTION_LONG);
			args.add(erpcPortPrefix);
		}
		if(!excludeMethods.isEmpty()){
			for(Entry<String, String> entry:excludeMethods.entrySet()){
				args.add("--" + ThriftServiceDecoratorConfiguration.EXCLUDE_METHODS_OPTION_LONG);
				args.add(entry.getKey() + ":" + entry.getValue());
			}
		}
		if(!includeMethods.isEmpty()){
			for(Entry<String, String> entry:includeMethods.entrySet()){
				args.add("--" + ThriftServiceDecoratorConfiguration.INCLUDE_METHODS_OPTION_LONG);
				args.add(entry.getKey() + ":" + entry.getValue());
			}
		}

		if(!excludeFields.isEmpty()){
			for(Entry<String, String> entry:excludeFields.entrySet()){
				args.add("--" + ThriftServiceDecoratorConfiguration.EXCLUDE_FIELDS_OPTION_LONG);
				args.add(entry.getKey() + ":" + entry.getValue());
			}
		}
		if(null != thriftServiceClass){
			args.add("--" + ThriftServiceDecoratorConfiguration.THRIFT_SERVICE_CLASS_OPTION_LONG);
			args.add(thriftServiceClass);
		}
		if(erpcForwardPort>0){
			args.add("--" + ThriftServiceDecoratorConfiguration.ERPC_FORWARD_PORT_OPTION_LONG);
			args.add(Integer.toString(erpcForwardPort));
		}
		if(erpcProxyPort>0){
			args.add("--" + ThriftServiceDecoratorConfiguration.ERPC_PROXY_PORT_OPTION_LONG);
			args.add(Integer.toString(erpcProxyPort));
		}
		if(defaultMaxLength>0){
			args.add("--" + ThriftServiceDecoratorConfiguration.ERPC_DEFAULT_MAX_LENGTH_OPTION_LONG);
			args.add(Integer.toString(defaultMaxLength));
		}
		if(errmsgMaxLength>0){
			args.add("--" + ThriftServiceDecoratorConfiguration.ERPC_ERRMSG_MAX_LENGTH_OPTION_LONG);
			args.add(Integer.toString(errmsgMaxLength));
		}
		if(binaryOutputSize>0){
			args.add("--" + ThriftServiceDecoratorConfiguration.ERPC_BINARY_OUTPUT_SIZE_OPTION_LONG);
			args.add(Integer.toString(binaryOutputSize));
		}
		if(null != extStructs){
			args.add("--" + ThriftServiceDecoratorConfiguration.EXTENSIVE_STRUCT_OPTION_LONG);
			args.add(extStructs);
		}
		if(null != excludeVMs){
			args.add("--" + ThriftServiceDecoratorConfiguration.EXCLUDE_VMS_OPTION_LONG);
			args.add(excludeVMs);
		}
		if(null != includeVMs){
			args.add("--" + ThriftServiceDecoratorConfiguration.INCLUDE_VMS_OPTION_LONG);
			args.add(includeVMs);
		}
		return args;
	}
}
